/**
*
* @file utils.c
*
* @brief misc utility functions
*
* Provide implementation for various generic utility functions
*
* Copyright ?2011 HID Corporation.  All rights reserved.
*
* This software is protected by copyright law and international treaties.
* Any unauthorized reproduction, distribution or use of the software is prohibited.
*
*/

#include <stdio.h>
#include <string.h>
#include <stddef.h>

#include "types.h"
#include "utils.h"
#include "asn1.h"
#include "tlv.h"


#ifdef LITTLE_ENDIAN
 
/// <summary>
/// reverse the byte content of a uint32_t value
/// </summary>
/// <remarks>
/// 0xDDCCBBAA becomes 0xAABBCCDD
/// </remarks>
/// <param name="val">input value</param>
/// <returns>reversed value</returns>
uint32_t swapbytes_u4(uint32_t val)
{
    uint32_t res;
    res =  val << 24;
    res |= (val << 8) & 0x00FF0000;
    res |= (val >> 8) & 0x0000FF00;
    res |= val >> 24;
    return (res);
}
#endif
/// <summary>
/// XOR [inOutBuff] (volatile) and [buff] (volatile or persistent) and store result in [inOutBuff] (volatile)
/// </summary>
/// <remarks>
/// [inOutBuff] = [inOutBuff] ^ [buff] 
/// </remarks>
/// <param name="inOutBuff"> input/output buffer 1 </param>
/// <param name="buff"> buffer 2 </param>
/// <param name="length"> operating length </param>
/// <returns> void </returns>
void utils_xor_buf(uint8_t* inOutBuff, uint8_t* buff, uint16_t length)
{
    uint16_t i;

    for (i = 0; i < length; i++) 
	{
        inOutBuff[i] ^= buff[i];
    }
}

/// <summary>
/// XOR [inOutBuff] (volatile) and [buff] (volatile or persistent) and store result in [inOutBuff] (volatile)
/// </summary>
/// <remarks>
/// [inOutBuff] = [inOutBuff] ^ [buff] 
/// </remarks>
/// <param name="inOutBuff"> input/output buffer 1 </param>
/// <param name="buff"> buffer 2 </param>
/// <param name="length"> operating length </param>
/// <returns> void </returns>
void utils_xor(uint8_t* inOutBuff, uint8_t* buff, uint16_t length)
{
    uint16_t i;

    for (i = 0; i < length; i++) {
        *inOutBuff ^= buff[i];
    }
}

/// <summary>
/// copy source buffer content into volatile destination buffer
/// </summary>
/// <param name="src">source buffer</param>
/// <param name="dst">destination buffer</param>
/// <param name="length">operating length</param>
/// <returns> void </returns>
void utils_copy(uint8_t* src, uint8_t* dst, uint16_t length)
{	
	if (src > dst) {
		uint16_t i;
    	for (i = 0; i < length; i++) {
        	dst[i] = src[i];
    	}
	} else {
		while (length != 0) {
			length--;
        	dst[length] = src[length];
		}		
	}
}

/// <summary>
/// fill the volatile destination buffer with the provided pattern
/// </summary>
/// <param name="dst">destination buffer</param>
/// <param name="length">operating length</param>
/// <param name="pattern">pattern byte</param>
void utils_fill(uint8_t* dst, uint16_t length, uint8_t pattern)
{
    uint16_t i;
    for (i = 0; i < length; i++) {
        dst[i] = pattern;
    }
}

/// <summary>
/// Compare the content of 2 buffers for equality
/// </summary>
/// <param name="array1">first buffer</param>
/// <param name="array2">second buffer</param>
/// <param name="length">operating length</param>
/// <returns>TRUE if equal, otherwise FALSE</returns>
uint8_t utils_compare(uint8_t* array1, uint8_t* array2, uint16_t length)
{
	uint32_t i;
	for (i = 0; i < length; i++) {
		if (array1[i] != array2[i]) {
			return FALSE;
		}
	}
	return TRUE;
}

/// <summary>
/// Compare the content of 2 buffers for equality (with length check)
/// </summary>
/// <param name="array1">first buffer</param>
/// <param name="array1Length">first buffer length</param>
/// <param name="array2">second buffer</param>
/// <param name="array2Length">second buffer length</param>
/// <returns>TRUE if length match and content is identical, otherwise FALSE</returns>
uint8_t utils_compare2(uint8_t* array1, uint16_t array1Length, uint8_t* array2, uint16_t array2Length)
{
	if (array1Length != array2Length) {
		return FALSE;
	} else {
		return utils_compare(array1, array2, array1Length);
	}		
}

/// <summary>
/// Extract uint16_t value (big-endian) at provided pointer
/// </summary>
/// <param name="buffer">input buffer</param>
/// <returns>(buffer[0] << 8) | buffer[1]</returns>
uint16_t utils_getU2(uint8_t* buffer)
{
	return (uint16_t)((buffer[0] << 8) + buffer[1]);
}

/// <summary>
/// Extract uint32_t value (big-endian) at provided pointer
/// </summary>
/// <param name="buffer">input buffer</param>
/// <returns>(buffer[0] << 24) |(buffer[1] << 16) | (buffer[2] << 8) | buffer[3]</returns>
uint32_t utils_getU4(uint8_t* buffer)
{
	return (uint32_t)(((uint32_t)utils_getU2(buffer) << 16) + utils_getU2(buffer + 2));
}

/// <summary>
/// Set uint16_t value at provider pointer (pointer on volatile memory)
/// </summary>
/// <param name="buffer">volatile destination buffer</param>
/// <param name="value">value to set</param>
void utils_setU2(uint8_t* buffer, uint16_t value)
{
   	buffer[0] = (uint8_t)(value >> 8);
   	buffer[1] = (uint8_t)value;
}

/// <summary>
/// Set uint32_t value at provider pointer (pointer on volatile memory)
/// </summary>
/// <param name="buffer">volatile destination buffer</param>
/// <param name="value">value to set</param>
void utils_setU4(uint8_t* buffer, uint32_t value)
{
    utils_setU2(buffer, value >> 16);
    utils_setU2(buffer + 2, (uint16_t)value);   	
}
 
/// <summary>
/// Return the Main-Significant-Byte index of the provided buffer
/// </summary>
/// <remarks>
/// indexing is big-endian ordered (idx=0 correspond to the left positioned byte)
/// </remarks>
/// <param name="buffer">input buffer</param>
/// <param name="bufferLength">operating length</param>
/// <returns>index of the first non-null byte</returns>
uint16_t utils_msbIndex(uint8_t* buffer, uint16_t bufferLength)
{
	uint16_t i;

	for (i = 0; i < bufferLength; i++) {
		if (buffer[i] != 0) {
			return i;
		}		
	}	

	return 0;
}
